package com.zbkj.common.utils;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang3.StringUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * Date时间工具类
 *
 * @author ywy
 * @since 2021-06-02
 */
public class DateUtil {

    /**
     * 例如:2018-12-28
     */
    public static final String DATE = "yyyy-MM-dd";
    /**
     * 例如:2018-12-28 10:00:00
     */
    public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
    /**
     * 例如:10:00:00
     */
    public static final String TIME = "HH:mm:ss";
    /**
     * 例如:10:00
     */
    public static final String TIME_WITHOUT_SECOND = "HH:mm";
    /**
     * 例如:2018-12-28 10:00
     */
    public static final String DATE_TIME_WITHOUT_SECONDS = "yyyy-MM-dd HH:mm";
    /**
     * 例如:2018-12
     */
    public static final String MONTH = "yyyy-MM";


    public static Date getRandomTime() {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //指定开始日期
            long start = sdf.parse("2021-06-10 00:00:00").getTime();
            //指定结束日期
            long end = sdf.parse("2022-11-01 00:00:00").getTime();

            //调用方法产生随机数
            long randomDate = nextLong(start, end);
            SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //long转Date
            Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(sd.format(new Date(randomDate)));
            System.out.printf("随机日期为:", date);
            return date;

        } catch (Exception e) {

        }
        return null;
    }

    public static long nextLong(long start, long end) {
        Random random = new Random();
        return start + (long) (random.nextDouble() * (end - start + 1));
    }


    /**
     * 将字符串日期转换为日期格式
     * <br/>
     * 自定义格式
     *
     * @param datestr
     * @param dateformat
     * @return
     */
    public static Date stringToDate1(String datestr, String dateformat) {
        SimpleDateFormat sdfTwo = new SimpleDateFormat(dateformat);
        Date date = null;
        try {
            date = sdfTwo.parse(datestr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }


    /**
     * 将字符串日期转换为日期格式
     * <br/>
     * 自定义格式
     *
     * @param datestr
     * @param dateformat
     * @return
     */
    public static Long stringToDate(String datestr, DateFormat dateformat) {
        Date date = null;
        try {
            date = dateformat.parse(datestr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date.getTime();
    }

    public static Long stringToDateS(String date, String pattern) {
        if (StringUtils.isBlank(pattern)) {
            pattern = DATE_TIME;
        }
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.parse(date, dtf).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 拼接上当前年月日
     *
     * @param time
     * @return
     */
    public static String getDateFormat(String time) {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);
        String dateNowStr = sdf.format(new Date());
        String dateNowStrTime = dateNowStr + " " + time;
        return dateNowStrTime;
    }


    /**
     * 校验当前时间点是否在时间段内(24小时)
     *
     * @param startTime 10:00
     * @param endTime   16:00
     */
    public static Boolean check(String startTime, String endTime){
        Long timeNew = System.currentTimeMillis();
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);
        SimpleDateFormat sdfTwo = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
        Date date = new Date();
        String dateNowStr = sdf.format(date);
        String dateNowStrStartTime = dateNowStr + " " + startTime;
        String dateNowStrEndTime = dateNowStr + " " + endTime;
        Long startLong = stringToDate(dateNowStrStartTime, sdfTwo);
        Long endLong = stringToDate(dateNowStrEndTime, sdfTwo);
        if (endLong < startLong) {
            endLong = endLong + 24 * 60 * 60 * 1000;
        }
        if (startLong <= timeNew && endLong >= timeNew) {
            return true;
        }
        return false;
    }

    /**
     * 校验当前时间点是否在任意时间段内
     *
     * @param startTime 2022-10-15 10:00
     * @param endTime   2022-10-15 16:00
     */
    public static Boolean checkNew(String startTime, String endTime) throws ParseException {
        Long timeNew = System.currentTimeMillis();
        SimpleDateFormat sdfTwo = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
        String dateNowStrStartTime = startTime;
        String dateNowStrEndTime = endTime;
        Long startLong = stringToDate(dateNowStrStartTime, sdfTwo);
        Long endLong = stringToDate(dateNowStrEndTime, sdfTwo);
        if (endLong < startLong) {
            endLong = endLong + 24 * 60 * 60 * 1000;
        }
        if (startLong <= timeNew && endLong >= timeNew) {
            return true;
        }
        return false;
    }


    /**
     * 校验当前时间点是否在时间段内(24小时)
     *
     * @param endTime 16:00
     */
    public static Long getLongTime(String endTime) throws ParseException {
        Long timeNew = System.currentTimeMillis();
        Date dateBase = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);
        SimpleDateFormat sdfTwo = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
        String dateNowStr = sdf.format(dateBase);
        String dateNowStrStartTime = sdfTwo.format(dateBase);
        String dateNowStrEndTime = dateNowStr + " " + endTime;
        Long startLong = stringToDate(dateNowStrStartTime, sdfTwo);
        Long endLong = stringToDate(dateNowStrEndTime, sdfTwo);
        if (endLong < startLong) {
            SimpleDateFormat sdfThree = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
            Date date = DateUtil.addDays(sdfThree.parse(dateNowStrEndTime), 1);
            endLong = date.getTime();
        }
        if (startLong <= timeNew && endLong >= timeNew) {
            return (endLong - timeNew) / 1000 / 60;
        }
        return 0L;
    }


    /**
     * 校验当前时间点是否在时间段内(24小时)
     *
     * @param endTime 16:00
     */
    public static String getEndTime(String endTime) throws ParseException {
        Date dateBase = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);
        SimpleDateFormat sdfTwo = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
        String dateNowStr = sdf.format(dateBase);
        String dateNowStrStartTime = sdfTwo.format(dateBase);
        String dateNowStrEndTime = dateNowStr + " " + endTime;
        Long startLong = stringToDate(dateNowStrStartTime, sdfTwo);
        Long endLong = stringToDate(dateNowStrEndTime, sdfTwo);
        if (endLong < startLong) {
            SimpleDateFormat sdfThree = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
            Date date = DateUtil.addDays(sdfThree.parse(dateNowStrEndTime), 1);
            return sdfTwo.format(date);
        }
        return dateNowStrEndTime;
    }

    /**
     * 计算两个时间段间隔的分钟
     *
     * @param startTime 10:00
     * @param endTime   16:00
     */
    public static Long calculateMinTime(String startTime, String endTime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);
        String dateNowStr = sdf.format(new Date());
        String dateNowStrStartTime = dateNowStr + " " + startTime;
        String dateNowStrEndTime = dateNowStr + " " + endTime;
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_WITHOUT_SECONDS);
        LocalDateTime parse1 = LocalDateTime.parse(dateNowStrStartTime, dateTimeFormatter);
        LocalDateTime parse2 = LocalDateTime.parse(dateNowStrEndTime, dateTimeFormatter);
        long minutes = Duration.between(parse1, parse2).toMinutes();
        if (minutes < 0) {
            SimpleDateFormat sdfThree = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
            Date date = DateUtil.addDays(sdfThree.parse(dateNowStrEndTime), 1);
            LocalDateTime parse3 = LocalDateTime.parse(sdfThree.format(date), dateTimeFormatter);
            minutes = Duration.between(parse1, parse3).toMinutes();
        }
        return minutes;
    }


    /**
     * 计算当前时间到结束时间间隔的分钟
     *
     * @param endTime 16:00
     */
    public static Long calculateCurrentTimeToEndTimeMin(String endTime) {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);
        String dateNow = sdf.format(new Date());
        String dateNowStrEndTime = dateNow + " " + endTime;

        SimpleDateFormat sdfCurrent = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
        String dateNowStr = sdfCurrent.format(new Date());
        String dateNowStrStartTime = dateNowStr;

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_WITHOUT_SECONDS);
        LocalDateTime parse1 = LocalDateTime.parse(dateNowStrStartTime, dateTimeFormatter);
        LocalDateTime parse2 = LocalDateTime.parse(dateNowStrEndTime, dateTimeFormatter);
        long minutes = Duration.between(parse1, parse2).toMinutes();
        return minutes > 0 ? minutes : 0L;
    }


    /**
     * @param hhmmdd
     * @return
     */
    public static Date formatDate(String hhmmdd) {
        Date parse = null;
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);
        SimpleDateFormat sdfTime = new SimpleDateFormat(DATE_TIME);
        String dateNowStr = sdf.format(new Date());
        String dateNowStrStartTime = dateNowStr + " " + hhmmdd;
        try {
            parse = sdfTime.parse(dateNowStrStartTime);
        } catch (Exception e) {

        }
        return parse;
    }


    /**
     * 判断两个时间是否相等
     *
     * @param oneTime
     * @param twoTime
     * @return
     */
    public static Boolean isEq(Date oneTime, Date twoTime) {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);
        String dateNowStrOne = sdf.format(oneTime);
        String dateNowStrTwo = sdf.format(twoTime);
        if (dateNowStrOne.equals(dateNowStrTwo)) {
            return true;
        }
        return false;
    }


    /**
     * 校验当前时间点是否在时间段内(24小时)
     *
     * @param startTime 2021-06-29 10:00
     * @param endTime   2021-06-29 16:00
     * @return
     */
    public static Boolean checkTwo(String startTime, String endTime) {
        Long timeNew = System.currentTimeMillis();
        SimpleDateFormat sdfTwo = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
        Long startLong = stringToDate(startTime, sdfTwo);
        Long endLong = stringToDate(endTime, sdfTwo);
        if (startLong <= timeNew && endLong >= timeNew) {
            return true;
        }
        return false;
    }


    /**
     * 计算两个日期之前相差多少分钟
     *
     * @param startTime 2021-06-29 10:00
     * @param endTime   2021-06-29 16:00
     * @return
     */
    public static Long getMinTimeByDate(String startTime, String endTime) {
        SimpleDateFormat sdfTwo = new SimpleDateFormat(DATE_TIME_WITHOUT_SECONDS);
        Long startLong = stringToDate(startTime, sdfTwo);
        Long endLong = stringToDate(endTime, sdfTwo);
        Long min = (endLong - startLong) / 1000L / 60L;
        min = min == 0 ? 1 : min + 1;
        return min;
    }


    /**
     * @return 返回当天的起始时间
     */
    public static Date getStartTime() {
        LocalDateTime now = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
        return localDateTime2Date(now);
    }

    /**
     * @return 返回当天的结束时间
     */
    public static Date getEndTime() {
        LocalDateTime now = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(999);
        return localDateTime2Date(now);
    }

    /**
     * @return 返回当天的起始时间
     */
    public static String getStringStartTime() {
        /**
         * 方法1
         */
        //LocalDateTime startToday = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        //String startTime = startToday.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        /**
         * 方法2
         */
        LocalDateTime now = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_TIME);
        Date date = localDateTime2Date(now);
        return sdf.format(date);
    }


    /**
     * @return 返回当天的结束时间
     */
    public static String getStringEndTime() {
        LocalDateTime now = LocalDateTime.now().withHour(23).withMinute(59).withSecond(59).withNano(999);
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_TIME);
        Date date = localDateTime2Date(now);
        return sdf.format(date);
    }


    /**
     * LocalDateTime类型转为Date
     *
     * @param localDateTime LocalDateTime object
     * @return Date object
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }


    /**
     * 传入long时间戳 ，转换成格式化的String类型时间
     *
     * @param time
     * @return
     */
    public static String timeOfLongToStr(Long time) {
        Assert.notNull(time, "time is null");
        DateTimeFormatter ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));
    }

    public static void main(String[] args) {
        System.out.println(timeOfLongToStr(System.currentTimeMillis()));
    }

    public static String timeOfLongToStr(Long time, String pattern) {
        Assert.notNull(time, "time is null");
        DateTimeFormatter ftf = DateTimeFormatter.ofPattern(pattern);
        return ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));
    }

    public static String timeOfDateToStr(Date date, String pattern) {
        if (date == null) return "";
        if (StringUtils.isBlank(pattern)) {
            pattern = DATE_TIME;
        }
        DateTimeFormatter ftf = DateTimeFormatter.ofPattern(pattern);
        return ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault()));
    }

    /**
     * 加天数
     *
     * @param daysToAdd 天数
     * @return Date
     */
    public static Date addDays(Date date, long daysToAdd) {
        LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        LocalDateTime localDateTime = dateTime.plusDays(daysToAdd);

        return localDateTime2Date(localDateTime);
    }


    /**
     * 获取本月的第一天或最后一天
     *
     * @return
     * @Param: [today, isFirst: true 表示开始时间，false表示结束时间]
     */
    public static String getStartOrEndDayOfMonth(LocalDate today, Boolean isFirst) {
        LocalDate resDate = LocalDate.now();
        if (today == null) {
            today = resDate;
        }
        Month month = today.getMonth();
        int length = month.length(today.isLeapYear());
        if (isFirst) {
            resDate = LocalDate.of(today.getYear(), month, 1);
        } else {
            resDate = LocalDate.of(today.getYear(), month, length);
        }
        return resDate.toString();
    }


    /**
     * StringTime转LocalDate
     *
     * @param dateTime
     * @return
     */
    public static LocalDate getLocalDateByStringTime(String dateTime) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate date = null;
        if (StrUtil.isBlank(dateTime)) {
            SimpleDateFormat sdf = new SimpleDateFormat(DATE);
            String dateNowStr = sdf.format(new Date());
            date = LocalDate.parse(dateNowStr, fmt);
        } else {
            date = LocalDate.parse(dateTime, fmt);
        }
        return date;
    }

    /**
     * 日期相隔天数 <br/>
     * endDate - startDate
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long getDiscrepancyDays(Date startDate, Date endDate) {
        LocalDate startDateInclusive = date2LocalDate(startDate);
        LocalDate endDateExclusive = date2LocalDate(endDate);
        return ChronoUnit.DAYS.between(startDateInclusive, endDateExclusive);
    }


    /**
     * Date 转 localDate
     *
     * @param date
     * @return
     */
    public static LocalDate date2LocalDate(Date date) {
        Instant instant = date.toInstant();
        ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
        LocalDate localDate = zdt.toLocalDate();
        return localDate;
    }


    /**
     * 获取本周的第一天或最后一天
     *
     * @param : [today, isFirst: true 表示开始时间，false表示结束时间]
     * @return
     */
    public static String getStartOrEndDayOfWeek(LocalDateTime today, Boolean isFirst) {
        LocalDateTime resDate = LocalDateTime.now();
        if (today == null) {
            today = resDate;
        }
        DayOfWeek week = today.getDayOfWeek();
        int value = week.getValue();
        if (isFirst) {
            resDate = today.minusDays(value - 1);
        } else {
            resDate = today.plusDays(7 - value);
        }
        return resDate.toString();
    }

    /**
     * 获取当前年月日时分秒时间
     *
     * @return
     */
    public static String getToDay() {
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateNowStr = sdf.format(d);
        return dateNowStr;
    }

    /**
     * 获取当前时间
     *
     * @return
     */
    public static String getToDay(String format) {
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        String dateNowStr = sdf.format(d);
        return dateNowStr;
    }

    /**
     * 获取当前日期
     *
     * @param pattern 格式，默认格式yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String getCurrentTime(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now();

        if (StringUtils.isEmpty(pattern)) {
            pattern = DATE_TIME;
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }

    /**
     * 格式化日期为字符串
     *
     * @param date    date
     * @param pattern 格式
     * @return 日期字符串
     */
    public static String format(Date date, String pattern) {
        if (date == null) {
            return null;
        }
        Instant instant = date.toInstant();

        if (StringUtils.isBlank(pattern)) {
            pattern = DATE_TIME;
        }
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 获取YYYY-MM-DD HH:mm:ss格式
     *
     * @return
     */
    public static String getTime() {
        SimpleDateFormat sdfTime = new SimpleDateFormat(DATE_TIME);
        return sdfTime.format(new Date());
    }

    /**
     * LocalDateTime ->String
     *
     * @param localDateTime
     * @return
     */
    public static String localDateTimeToString(LocalDateTime localDateTime, String pattern) {
        if (StringUtils.isBlank(pattern)) {
            pattern = DATE_TIME;
        }
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 将 Date 转为 LocalDate
     *
     * @param date
     * @return java.time.LocalDate;
     */
    public static LocalDate dateToLocalDate(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 将 Date 转为 LocalDateTime
     *
     * @param date
     * @return java.time.LocalDateTime;
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 获取年龄
     * @param userBirthday
     * @return
     */
    public static Integer calculateAge(Date userBirthday) {
        return calculateAge(LocalDateTime.ofInstant(userBirthday.toInstant(), ZoneId.systemDefault()).toLocalDate());
    }

    public static Integer calculateAge(LocalDateTime userBirthday) {
        return calculateAge(userBirthday.toLocalDate());
    }
    public static Integer calculateAge(LocalDate userBirthday) {
        LocalDate localDate = LocalDate.now();
        return Math.toIntExact(ChronoUnit.YEARS.between(userBirthday, localDate));
    }


    /**
     * 星座名称
     */
    public static final String[] CONSTELLATION_ARR = { "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "魔羯座" };
    /**
     * 每跟月星座界限
     */
    public static final int[] CONSTELLATION_EDGE_DAY = { 20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22 };


    /**
     * 根据日期获取星座
     * @param userBirthday
     * @return
     */
    public static String findConstellationByDate(Date userBirthday) {
        return findConstellationByDate(LocalDateTime.ofInstant(userBirthday.toInstant(), ZoneId.systemDefault()).toLocalDate());
    }
    public static String findConstellationByDate(LocalDate userBirthday) {
        String constellation;
        int month = userBirthday.getMonthValue();
        int day = userBirthday.getDayOfMonth();
        if (day < CONSTELLATION_EDGE_DAY[month-1]) {
            month = month - 1;
        }
        constellation = CONSTELLATION_ARR[11];
        if (month > 0) {
            constellation = CONSTELLATION_ARR[month-1];
        }
        return constellation;
    }




}
